package org.vacoor.xqq.core.mod.impl;

import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.xqq.core.mod.MessageReceiver;
import org.vacoor.xqq.core.msg.chatmsg.MsgElement;
import org.vacoor.xqq.core.msg.EventBusHolder;
import org.vacoor.xqq.core.bean.ChatToken;
import org.vacoor.xqq.core.http.HttpRequestor;
import org.vacoor.xqq.core.http.Request;
import org.vacoor.xqq.core.http.RequestCallbackAdapter;
import org.vacoor.xqq.core.http.Response;
import org.vacoor.xqq.core.msg.chatmsg.*;
import org.vacoor.xqq.core.msg.eventmsg.*;
import org.vacoor.xqq.core.msg.req.ReplyMsg;
import org.vacoor.xqq.core.util.Jacksons;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

/**
 * 消息接收器
 * {"retcode":0,"result":[{"poll_type":"system_message","value":{"seq":52786,"type":"verify_required","uiuin":"","from_uin":4077369286,"account":2213328508,"onMsg":"","allow":1,"stat":20}}]}
 *
 * <p/>
 * User: vacoor
 */
public class SimpleMessageReceiver implements MessageReceiver {
    public static final Logger logger = LoggerFactory.getLogger(SimpleMessageReceiver.class);
    public static final String POLL_URL = "http://d.web2.qq.com/channel/poll2";

    private boolean receive = false;
    private ChatToken token;

    // 为了保持不断线的心跳
    private Timer beatTimer = new Timer(1000 * 60 * 30, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            ReplyMsg beatMsg = new ReplyMsg();
            beatMsg.setTo(2213328508L);
            beatMsg.getMsgBody().addElement(
                    MsgElement.createTextElement("beat")
            );
            EventBusHolder.getEventBus().post(beatMsg);
        }
    });


    public SimpleMessageReceiver(ChatToken token) {
        this.token = token;
        EventBusHolder.getEventBus().register(this);
    }

    @Override
    public void start(){
        start(1000);
        beatTimer.start();
    }

    /**
     * @param minInterval 毫秒
     */
    @Override
    public void start(int minInterval) {
        if (receive) {
            return;
        }
        logger.info("启动消息接收...");

        receive = true;
        receive(minInterval);
    }

    @Override
    public void stop() {
        receive = false;
        beatTimer.stop();
    }

    private void receive(final int minInterval) {
        if (!receive) {
            return;
        }
        String jsonParam = Jacksons.createObjectNode()
//                .put("ptwebqq", token.getPtwebqq())
                .put("clientid", token.getClientId())
                .put("psessionid", token.getPsessionId())
                .put("key", "").toString();

        final long start = System.currentTimeMillis();
        HttpRequestor.getInstance().send(
                new Request(POLL_URL, Request.HttpMethod.POST)
                        .addHeader("Referer", "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=3")
                        .addHeader("Connection", "keep-alive")
                        .addHeader("MsgBody-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                        .addParameter("r", jsonParam),
                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) throws IOException {
                        resolve(resp.getContent().asString());

                        final long time = System.currentTimeMillis() - start;
                        if (time < minInterval) {
                            try {
                                Thread.sleep(minInterval - time);
                            } catch (InterruptedException e) {
                            }
                        }
                        receive(minInterval);
                    }
                }
        );
    }

    public void resolve(String message) {
        logger.debug("Resolve message: {}", message);
        if (0 == message.length()) {
            logger.warn("onMsg length is zero: {}", message);
        }
        JsonNode root = Jacksons.readTree(message);
        //
        int retcode = root.get("retcode").asInt();
        // 102 正常超时,无消息 {"retcode":102,"errmsg":""}
        if (retcode == 102) {
            return;
        }
        // 正常结果处理
        switch (retcode) {
            // 非法请求 {"retcode":103,"errmsg":""} eg: Referer 头错误
            case 103:
                logger.warn("非法请求, {}", root);
                break;
            // 102 正常超时,无消息 {"retcode":102,"errmsg":""}
            case 102:   // 无消息
                break;
            case 0:     // 有消息返回
                JsonNode result = root.get("result");
                if (result.isNull() || !result.isArray()) {
                    logger.warn("未知消息格式: {}", result);
                }

                // 遍历所有结果
                for (JsonNode msg : root.get("result")) {
                    String type = msg.get("poll_type").asText();
                    JsonNode value = msg.get("value");

                    Class<?> msgType = resolveMessageType(type);

                    Object m = null;
                    if (UnknownMsg.class == msgType) {
                        m = new UnknownMsg(value.toString());

                        logger.warn("不能解析消息: {}", m);
                    } else {
                        m = Jacksons.deserialize(value.toString(), msgType);
                        if (m == null) {
                            m = new UnknownMsg(value.toString());
                            logger.warn("未知消息: {}", m);
                        }
                    }
                    EventBusHolder.getEventBus().post(m);
                }
                break;

            case 109:
            case 110:
                logger.debug("客户端已经主动退出: {}", root);
                this.stop();
                break;

            // 服务器要求更换ptwebqq, 并出发hottag {"retcode":116,"p":"457dc95eb9ea1147d99197a093d74496b088052f3109046d"}
            case 116:
                logger.debug("服务器要求更换ptwebqq,并触发hottag: {}", root);
                break;
            case 100:     //NotLogin
                this.stop();
                logger.debug("NotLogin: {}", root);
                break;
            case 120:     // ReLinkFailure
            case 121:
                this.stop();
                logger.debug("ReLinkFailure: {}", root);
                break;
            default:
                logger.warn("未知响应: {}", root);
        }
    }

    private Class<?> resolveMessageType(String type) {
        Class<?> result = UnknownMsg.class;
        // 联系人消息
        if ("message".equalsIgnoreCase(type)) {
            result = ContactMsg.class;

            // 群消息
        } else if ("group_message".equalsIgnoreCase(type)) {
            result = GroupMsg.class;

            // 讨论组消息
        } else if ("discu_message".equalsIgnoreCase(type)) {
            result = DiscuMsg.class;

            // 临时会话
        } else if ("sess_message".equalsIgnoreCase(type)) {
            result = SessMsg.class;

            // 系统消息
        } else if ("system_message".equalsIgnoreCase(type)) {

            // 窗口抖动
        } else if ("shake_message".equalsIgnoreCase(type)) {
            result = ShakeMsg.class;

            // 输入消息
        } else if ("input_notify".equalsIgnoreCase(type)) {
            result = InputNotifyMsg.class;

            // 好友状态改变
        } else if ("buddies_status_change".equalsIgnoreCase(type)) {
            result = StatusChangeMsg.class;

            // tip 消息(广告)
        } else if ("tips".equalsIgnoreCase(type)) {

            // 踢出
        } else if ("kick_message".equals(type)) {
            this.stop();
            result = KickMsg.class;
        }
        return result;
    }
}
